﻿using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Threading;
using CommonTypes.Server;
using Server.Model;

namespace Server.Services.RemoteObjects
{
    public class PMToServer : MarshalByRefObject, IPMToServer
    {
        private ServerData _serverData;

        private ClientToServer _clientToServerProxy;

        private ServerToServer _serverToServerProxy;

        public PMToServer( ServerData sd, ClientToServer clientToServer, ServerToServer serverToServer )
        {
            _serverData = sd;
            _clientToServerProxy = clientToServer;
            _serverToServerProxy = serverToServer;
        }

        private delegate void PingProtocol( bool StartAsPrimary, AutoResetEvent ev, ServerData serverData );

        private void setPrimary( )
        {
            _serverData.State = ServerState.ESTABLISHED;
            System.Console.WriteLine( "I'm being empowered primary!" );

            _serverData.ServersInformation.PrimaryId = _serverData.ServerId;
            _serverData.ServersInformation.Primary = true;

            System.Console.WriteLine( "I'm the primary!" );
            PingProtocol proto = PingManager.managePingProtocol;
            proto.BeginInvoke( true, _serverData.Terminate, _serverData, null, null );

            foreach( KeyValuePair<String, IServerToServer> servers in _serverData.ServersInformation.ServersProxy )
            {
                if( ( servers.Key != _serverData.ServerId ) && ( _serverData.ServersInformation.ActiveServers[ servers.Key ] ) )
                {
                    servers.Value.registerServer( _serverData.ServerId );
                }
            }
        }

        private void setSecondary( )
        {
            _serverData.State = ServerState.ESTABLISHED;
            _serverData.ServersInformation.PrimaryId = BullyProtocol.obtainPrimary( _serverData );
            _serverData.ServersInformation.Primary = false;
            _serverData.PingInformation.NumberOfTries = 0;
            _serverData.PingInformation.PingReceived = true;
            _serverData.Terminate.Reset( );
            _serverData.ServersInformation.ServersProxy[ _serverData.ServersInformation.PrimaryId ].registerServer( _serverData.ServerId );

            foreach( KeyValuePair<String, IServerToServer> servers in _serverData.ServersInformation.ServersProxy )
            {
                if( ( servers.Key != _serverData.ServerId ) && ( servers.Key != _serverData.ServersInformation.PrimaryId ) )
                {
                    servers.Value.registerServer( _serverData.ServerId );
                }
            }

            System.Console.WriteLine( "I'm an secondary!" );
            PingProtocol proto = PingManager.managePingProtocol;
            proto.BeginInvoke( false, _serverData.Terminate, _serverData, null, null );
        }

        public bool Connect( )
        {
            if( _serverData.IsConnected == false )
            {
                _serverData.State = ServerState.ADDREMOVE;
                RemotingServices.Marshal( _clientToServerProxy, "ClientToServer" );
                RemotingServices.Marshal( _serverToServerProxy, "ServerToServer" );
                _serverData.Operations.Clear( );
                if( BullyProtocol.addServer( _serverData ) )
                    setPrimary( );
                else
                    setSecondary( );
                _serverData.IsConnected = true;
                Console.WriteLine( "Server Successfully connected." );
                return true;
            }
            else
                return false;
        }

        public bool Disconnect( )
        {
            if( _serverData.IsConnected == true )
            {
                RemotingServices.Disconnect( _serverToServerProxy );
                RemotingServices.Disconnect( _clientToServerProxy );
                PingManager.terminatePingManager( _serverData );
                _serverData.IsConnected = false;
                Console.WriteLine( "Server Successfully disconnected." );
                return true;
            }
            else
                return false;
        }

        public override object InitializeLifetimeService( )
        {
            return null;
        }
    }
}